
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

//#include "sha.h"
#include "bootimg.h"

int main(int argc, char **argv)
{
    FILE *img_file;
    char *img_name, *img_buf;
    size_t ret, img_size;
    boot_img_hdr hdr;

    // copy boot.img to memcpy
    img_name = argv[1];
    img_file = fopen(img_name, "rb");
    if(img_file == NULL) {
        printf("open file error\n");
        exit(-1);
    }

    fseek(img_file, 0, SEEK_END);
    img_size = ftell(img_file);

    img_buf = (char *)malloc(img_size);

    fseek(img_file, 0, SEEK_SET);
    ret = fread((void *)img_buf, img_size, 1, img_file);
    if(ret != 1) {
        printf("read file error\n");
        exit(-1);
    }
    
    fclose(img_file);
    img_file = NULL;

    // copy boot.img header struct
    memcpy((void *)&hdr, (void *)img_buf, sizeof(hdr));

    // show header info
    printf("\n+++++++++++++++++++++++++++++++++++++++++++++++\n");

    printf("kernel size: %i\n", hdr.kernel_size);
    printf("kernel addr: 0x%08x\n", hdr.kernel_addr);

    printf("ramdisk size: %i\n", hdr.ramdisk_size);
    printf("ramdisk addr: 0x%08x\n", hdr.ramdisk_addr);

    printf("second size: %i\n", hdr.second_size);
    printf("second addr: 0x%08x\n", hdr.second_addr);
    
    printf("tags addr: 0x%08x\n", hdr.tags_addr);
    printf("page size: %i\n", hdr.page_size);

    printf("unused[2]: %i %i\n", 
           hdr.unused[0], hdr.unused[1]);
    
    printf("name: %s\n", hdr.name);
    printf("cmdline: %s\n", hdr.cmdline);

    printf("id[8]: %08x %08x %08x %08x\n", 
           hdr.id[0], hdr.id[1], hdr.id[2], hdr.id[3]);
    printf("       %08x %08x %08x %08x\n", 
           hdr.id[4], hdr.id[5], hdr.id[6], hdr.id[7]);

    if(hdr.second_size != 0) {
        printf("found a secondary file after the ramdisk image.\n"
               "according to the spec (mkbootimg.h) this file can exist,\n"
               "but this program is not designed to deal with this scenario.\n");
        exit(-1);
    }

    // write kernel, ramdisk
    FILE *out_file;
    char out_name[64];
    int page_size;
    int kernel_pages, ramdisk_pages;
    int kernel_offset, ramdisk_offset;

    if(*(int *)(img_buf + hdr.page_size) == 0) {
	  printf("\n+++++++++++++++++++++++++++++++++++++++++++++++\n");
	  printf("page_size in bootimg header struct is %i,\n"
			  "but the real value should be %i\n", hdr.page_size, hdr.page_size * 2);
          hdr.page_size *= 2;
    }

    kernel_pages = (hdr.kernel_size + hdr.page_size - 1) / hdr.page_size;
    ramdisk_pages = (hdr.ramdisk_size + hdr.page_size - 1) / hdr.page_size;

    kernel_offset = hdr.page_size;
    ramdisk_offset = kernel_offset + kernel_pages * hdr.page_size;

    snprintf(out_name, sizeof(out_name), "kernel");
    printf("\n+++++++++++++++++++++++++++++++++++++++++++++++\n");
    printf("write kernel: %s\n", out_name);
    printf("    pages: %i, offset: 0x%08x\n", kernel_pages, kernel_offset);

    out_file = fopen(out_name, "wb");
    ret = fwrite(img_buf + kernel_offset, hdr.kernel_size, 1, out_file);
    if(ret != 1) {
        printf("write %s error\n", out_name);
    }
    fclose(out_file);

    snprintf(out_name, sizeof(out_name), "ramdisk.img");
    printf("\n+++++++++++++++++++++++++++++++++++++++++++++++\n");
    printf("write ramdisk: %s\n", out_name);
    printf("    pages: %i, offset: 0x%08x\n", ramdisk_pages, ramdisk_offset);
    
    out_file = fopen(out_name, "wb");
    ret = fwrite(img_buf + ramdisk_offset, hdr.ramdisk_size, 1, out_file);
    if(ret != 1) {
        printf("write %s error\n", out_name);
    }
    fclose(out_file);
}
